/*******************************************************************************
 * Copyright (c) 2024.
 * IWIN-FINS Lab, Shanghai Jiao Tong University, Shanghai, China.
 * All rights reserved.
 ******************************************************************************/

#ifndef BSP_CAN_H
#define BSP_CAN_H

#include "Board.h"
#include "stm32h7xx_hal_fdcan.h"

class BSP_CANs {
public:
    static BSP_CANs &GetInstance() {
        static BSP_CANs instance;
        return instance;
    }

private:
    BSP_CANs() {
        PeripheralsInit::GetInstance();
        BSP_CANs_Setup();
    }

    void BSP_CANs_Setup() {
    }
};

template<uint8_t ID>
class BSP_CAN {
public:
    static BSP_CAN &GetInstance() {
        static BSP_CAN instance;
        return instance;
    }

    void Transmit(FDCAN_TxHeaderTypeDef *Header, const uint8_t *data);

    void HAL_FDCAN_ConfigFilter(FDCAN_HandleTypeDef* hfdcan, FDCAN_FilterTypeDef* filterConfig);
    void Receive(FDCAN_RxHeaderTypeDef *Header, uint8_t *data);

private:
    BSP_CAN() {
        static_assert(ID > 0 && ID <= CAN_BUS_MAXIMUM_COUNT && BSP_CANList[ID] != nullptr, "Invalid CAN ID");
        BSP_CANs::GetInstance();
        BSP_CAN_Setup();
    }

    void PeriphralInit() {
        __HAL_FDCAN_ENABLE_IT(BSP_CANList[ID], FDCAN_IT_RX_FIFO0_NEW_MESSAGE);
        __HAL_FDCAN_ENABLE_IT(BSP_CANList[ID], FDCAN_IT_RX_FIFO0_WATERMARK);

        FDCAN_FilterTypeDef canFilter;
        canFilter.IdType = FDCAN_STANDARD_ID;
        canFilter.FilterIndex = 0;
        canFilter.FilterType = FDCAN_FILTER_MASK;
        canFilter.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
        canFilter.FilterID1 = 0x000;
        canFilter.FilterID2 = 0x000;
        canFilter.RxBufferIndex = FDCAN_FILTER_TO_RXBUFFER;
        canFilter.IsCalibrationMsg = FDCAN_FILTER_TO_RXBUFFER;

        switch (ID) {
            case 1: canFilter.FilterIndex = 0; break;
            case 2: canFilter.FilterIndex = 14; break;
        }

        HAL_FDCAN_ConfigFilter(BSP_CANList[ID], &canFilter);

        HAL_FDCAN_Start(BSP_CANList[ID]);
    }

    void BSP_CAN_Setup() {
        PeriphralInit();
    }
};

template<uint8_t ID>
void BSP_CAN<ID>::Receive(FDCAN_RxHeaderTypeDef *Header, uint8_t *data) {
    // 实现接收逻辑
}

template<uint8_t ID>
void BSP_CAN<ID>::Transmit(FDCAN_TxHeaderTypeDef *Header, const uint8_t *data) {
    if (HAL_FDCAN_AddMessageToTxFifoQ(BSP_CANList[ID], Header, data) != HAL_OK) {
        // 处理传输错误
    }
}

#endif